#ifndef __DRIVER_RTL8139_H
#define __DRIVER_RTL8139_H

#include <arch/pci.h>
#include<os/dma.h>

#define DRIVER_NAME "network-rtl8139"
#define DRIVER_VERSION "0.1"
#define DEVICE_NAME "network"

#define ETH_ALEN 6         //mac address lenght
#define ETH_ZLEN 60        //data min lenght that no contains CRC check
#define ETH_DATA_LEN 1500  //frame data max lenght
#define ETH_FRAME_LEN 1514 //frame lenght that no contains CRC check

//PCI rtl8139 config
#define RTL8139_VENDOR_ID 0x10ec
#define RTL8139_DEVICE_ID 0x8139

//max support ethernet frame size
#define MAX_ETH_FRAME_SIZE 1536

#define RX_BUFF_IDX 2                       //32K ring
#define RX_BUFF_LEN (8192 << RX_BUFF_IDX)
#define RX_BUFF_PAD 16                      //padding 16bytes
#define RX_BUFF_WRAP_PAD 2048

//receive buffer total len
#define RX_BUFF_TOTAL_LEN (RX_BUFF_LEN + RX_BUFF_PAD + RX_BUFF_WRAP_PAD)

//number of tx descriptor register
#define NUM_TX_DESC 4

//Tx buffer size
#define TX_BUFF_SIZE MAX_ETH_FRAME_SIZE
//Tx buffer total len
#define TX_BUFF_TOTAL_LEN (TX_BUFF_SIZE * NUM_TX_DESC)

//PCI Tuning Parameters
#define TX_FIFO_THRESH 256

//net features
#define NET_FEATURE_RXALL (1 << 0) //receive all packet(no check)
#define NET_FEATURE_RXFCS (1 << 1) //receive all packet(within check)

typedef enum
{
    RTL8139 = 0x0,
    RTL8129,
} board_t;

//offset of rtl8139 register in PCI base
enum rtl8139_reg
{
    MAC0 = 0x0,             //ethernet hardware address
    MAR0 = 0x8,             //multicast filter
    TX_STATUS0 = 0x10,      //transmit status
    TX_ADDR0 = 0x20,        //tx start address
    RX_BUFF = 0x30,         //rx buffer start address
    CHIP_CMD = 0x37,        //command register
    RX_BUFF_PTR = 0x38,     //current address of packet read
    RX_BUFF_ADDR = 0x3A,    //current receive buffer address
    INTR_MASK = 0x3C,       //interrupt mask register
    INTR_STATUS = 0x3E,     //interrupt status register
    TX_CONFIG = 0x40,       //transmit config
    RX_CONFIG = 0x44,       //receive config
    TIMER = 0x48,           //timer counter
    RX_MISSED = 0x4C,       //write clears
    CFG9346 = 0x50,          //93C46 command register
    CONFIG0 = 0x51,         //config register 0
    CONFIG1 = 0x52,         //config register 1
    TIMER_INTERRUPT = 0x54, //timer interrupt
    MEDIA_STATUS = 0x58,    //media status register
    CONFIG3 = 0x59,         //config register 3
    CONFIG4 = 0x5A,         //config register 4
    HLT_CTL = 0x5B,
    MULTI_INTR = 0x5C,        //multipe interrupt select
    TX_SUMMARY = 0x60,        //transmit status of all descripts
    BASIC_MODE_CTRL = 0x62,   //base mode control register
    BASIC_MODE_STATUS = 0x64, //base mode status
    NWAY_ADVERT = 0x66,
    NWAY_LPAR = 0x67,
    NWAY_EXPANDSION = 0x6A,
    FIFOTMS = 0x70, //fifo contorl and test
    CSCR = 0x74,    //chip status and configuration register
    PARA7B = 0x78,
    FLASH_REG = 0xD4, //communication with Flash ROM
    PARA7C = 0x7c,    //magic transceiver parameter register
    CONFIG5 = 0xD8,   //config register 5
};

enum clear_bit_mask
{
    MULTI_INT_CLEAR = 0xF000,
    CHIP_CMD_CLEAR = 0xE2,
    CONFIG1_CLEAR = (1 << 7) | (1 << 6) | (1 << 3) | (1 << 2) | (1 << 1),
};

//comand bits
enum chip_cmd_bit
{
    CMD_RESET = 0x10,
    CMD_RX_ENABLE = 0x08,
    CMD_TX_ENABLE = 0x04,
    CMD_BUFFER_EMPTY = 0x01,
};

//interrupt status bits
enum intr_status_bit
{
    PCI_ERR = 0x8000,     //a system error on pci bus
    PCS_TIMEOUT = 0x4000, //timeout
    RX_FIFO_OVER = 0x40,  //rx fifo overflow
    RX_UNDERRUN = 0x20,   //rx buffer empty or link chanaged
    RX_OVERFLOW = 0x10,   //rx buffer overflow
    TX_ERR = 0x08,        //tx error
    TX_OK = 0x04,         //tx ok
    RX_ERR = 0x02,        //rx error
    RX_OK = 0x01,         //rx ok
    RX_ACK_BITS = RX_FIFO_OVER | RX_OVERFLOW | RX_OK,
};

//transmit status bits
enum tx_status
{
    TX_HOST_OWNS = 0x2000,
    TX_UNDERRUN=0x4000,
    TX_STAT_OK = 0x8000,
    TX_OUT_OF_WINDOWS = 0x20000000,
    TX_ABORTED = 0x40000000,
    TX_CARRIER_LOST = 0x80000000,
};

//receive status bitsa
enum rx_status_bits
{
    RX_MULTICAST = 0x8000,  //indicate multicast address packet reserved
    RX_PHYSICAL = 0x4000,   //indicate physical address match
    RX_BROADCAST = 0x2000,  //indicate broadcast address packet reserved
    RX_BAD_SYMBOL = 0x0020, //indicate invalid symbol
    RX_RUNT = 0x0010,       //indicate receive packet lenght low than 64 bytes
    RX_TO_LONG = 0x0008,    //indicate size of recevice packet exceeds 4k bytes
    RX_CRC_ERR = 0x0004,    //indicate CRC error occuse on receive packet
    RX_BAD_ALIGN = 0x0002,  //indicate frame alignment error on receive packet
    RX_STATUS_OK = 0x0001,  //indicate a good packet is receive
};

//receive mode bits in rx_config register
enum rx_mode_bits
{
    ACCEPT_ERR = 0x20,            //accept error packet
    ACCEPT_RUNT = 0x10,           //accept packet that low than 64 bytes
    ACCEPT_BROADCAST = 0x08,      //accept broadcast packet
    ACCEPT_MULTICAST = 0x04,      //accept multicase packet
    ACCEPT_PHYSICAL_MATCH = 0x02, //accept physical address match packet
    ACCEPT_ALL = 0x01,            //aceept all packet
};

//transmit config bits
enum tx_config_bits
{
    TX_IFG_SHIFT = 24,
    TX_IFG84 = (0 << TX_IFG_SHIFT), //8.4us / 840ns (10 / 100Mbps)
    TX_IFG88 = (1 << TX_IFG_SHIFT), //8.8us / 880ns (10 / 100Mbps)
    TX_IFG92 = (2 << TX_IFG_SHIFT), //9.2us / 920ns (10 / 100Mbps)
    TX_IFG96 = (3 << TX_IFG_SHIFT), //9.6us / 960ns (10 / 100Mbps)

    TX_LOOP_BACK = (1 << 18) | (1 << 17), //enable loookback test mode
    TX_CRC = (1 << 16),                   //disable Tx packet CRC append
    TX_CLEAR_ABORT = (1 << 0),            //clear abort
    TX_DMA_SHIFT = 8,                     //DMA burst vaule shift
    TX_DMA_1024 = (6 << TX_DMA_SHIFT),    //Dma brust value 1024
    TX_RETRY_SHIFT = 4,                   //transmit retry count in multiple of 16 shift
    TX_RETRY_8 = (8 << TX_RETRY_SHIFT),   //retries=16+(TX_RETRY*16)

    TX_VERSION_MASK = 0x7C800000, //mark out version bits
};

enum config1_bits
{
    CFG1_PM_ENABLE = 0x01,   //power manager enable
    CFG1_VPD_ENABLE = 0x02,  //enable VPD (vitual product data) store in 93C46
    CFG1_PIO = 0x04,         //pci i/o space mode
    CFG1_MMIO = 0x08,        //pci memory map io mode
    CFG1_LWAKE = 0x10,       //LWAKE active mode
    CFG1_DRIVER_LOAD = 0x20, //indicate driver load
    CFG1_LED0 = 0x40,        //LED pin
    CFG1_LED1 = 0x80,        //LED pin
    SLEEP = (1 << 1),        //only on 8139,8139A
    PWRDN = (1 << 0),        //only on 8139,8139A
};

enum config3_bits
{
    CFG3_FAST_ENABLE = (1 << 0),     // fast back to back
    CFG3_FUNCTION_ENABLE = (1 << 1), //enable cardBus function register
    CFG3_CLKRUN_ENABLE = (1 << 2),   //enable CLKRUN
    CFG3_CARD_BUS_ENABLE = (1 << 3), //enable CardBus register
    CFG3_LINK_UP = (1 << 4),         //wake up on link up
    CFG3_MAGIC = (1 << 5),           //wake up on magic packet
    CFG3_PARM_ENABLE = (1 << 6),     //software can set twister paramenters
    CFG3_GNT = (1 << 7),             //delay 1 clock from PCI GNT signal
};

enum config4_bits
{
    CFG4_LWPTN = (1 << 2), //not on 8139,8139A
};

enum config5_bits
{
    CFG5_PME_STATUS = (1 << 0), //pci reset PME status
    CFG5_LANWAKE = (1 << 1),    //enable LANWAKE signal
    CFG5_LDPS = (1 << 2),       //enable link down power save
    CFG5_FIFOADDR = (1 << 3),   //realtek internal SRAM testing
    CFG5_UWF = (1 << 4),        //accept unicat wakeup frame
    CFG5_MWF = (1 << 5),        //accept multicast wakeup frame
    CFG5_BWF = (1 << 6),        //accept broadcast wakeup frame
};

enum rx_config_bits
{
    //rx fifo threshold
    RX_CFG_FIFO_SHIFT = 13,
    RX_CFG_FIFO_NONE = (7 << RX_CFG_FIFO_SHIFT),

    //max DMA brust
    RX_CFG_DMA_SHIFT = 8,
    RX_CFG_DMA_UNLIMITED = (7 << RX_CFG_DMA_SHIFT),

    //rx ring buffer length
    RX_CFG_RECV_8K = (0 << 11),
    RX_CFG_RECV_16K = (1 << 11),
    RX_CFG_RECV_32K = (1 << 12),
    RX_CFG_RECV_64K = (1 << 11) | (1 << 12),

    //disable packet wrap at end of Rx buffer
    RX_NO_WRAP = (1 << 7),
};

//twister tuning parameters from RealTek
enum cscr_bits
{
    CSCR_LINK_OK = 0x0400,
    CSCR_LINK_CHANGE = 0x0800,
    CSCR_LINK_STATUS = 0x0F00,
    CSCR_LINK_DONW_OFF_CMD = 0x003c0,
    CSCR_LINK_DOWN_CMD = 0x0f3c0,
};

//9346 config bits
enum config9346_bits
{
    CFG9346_LOCK = 0x00,
    CFG9346_UNLOCK = 0xC0,
};

//max chip info number
#define CHIP_INFO_NUM 10

enum chip_flags
{
    HAS_HTL_CLK = (1 << 0),
    HAS_LWAKE = (1 << 1),
};

#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
    (b30 << 30 | b29 << 29 | b28 << 28 | b27 << 27 | b26 << 26 | b23 << 23 | b22 << 22)

#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)

typedef enum
{
    CHIP_RTL8139 = 0,
    CHIP_RTL8139_K,
    CHIP_RTL8139A,
    CHIP_RTL8139A_6,
    CHIP_RTL8139B,
    CHIP_RTL8130,
    CHIP_RTL8139C,
    CHIP_RTL8100,
    CHIP_RTL8100B_8139D,
    CHIP_RTL8101,
} chip_t;

typedef struct
{
    const char *name;
    uint32_t version;
    uint32_t flags;
} chip_info_t;

static const chip_info_t rtl_chipinfo[CHIP_INFO_NUM] = {
    {"RTL-8139", HW_REVID(1, 0, 0, 0, 0, 0, 0), HAS_HTL_CLK},
    {"RTL-8139 rev K", HW_REVID(1, 1, 0, 0, 0, 0, 0), HAS_HTL_CLK},
    {"RTL-8139A", HW_REVID(1, 1, 1, 0, 0, 0, 0), HAS_HTL_CLK},
    {"RTL-8139A rev G", HW_REVID(1, 1, 1, 0, 0, 0, 0), HAS_HTL_CLK},
    {"RTL-8139B", HW_REVID(1, 1, 1, 1, 0, 0, 0), HAS_LWAKE},
    {"RTL-8130", HW_REVID(1, 1, 1, 1, 1, 0, 0), HAS_LWAKE},
    {"RTL-8139C", HW_REVID(1, 1, 1, 0, 1, 0, 0), HAS_LWAKE},
    {"RTL-8100", HW_REVID(1, 1, 1, 1, 0, 1, 0), HAS_LWAKE},
    {"RTL-8100B/8139D", HW_REVID(1, 1, 1, 0, 1, 0, 1), HAS_HTL_CLK | HAS_LWAKE},
    {"RTL-8101", HW_REVID(1, 1, 1, 0, 1, 1, 1), HAS_LWAKE},
};

typedef struct rtl_extra_status
{
    uint64_t early_rx;
    uint64_t txBuffMap;
    uint64_t TxTimeout;
    uint64_t rx_lost_in_ring;
} rtl_extra_status_t;

typedef struct rtl8139_sttaus
{
    uint64_t packets;
    uint64_t bytes;
} rtl8139_status_t;



typedef struct
{
    //error record
    uint64_t tx_error;          //transmit error records
    uint64_t tx_aborted_errors; //transmit abort records
    uint64_t tx_carrier_errors; //transmit carrier errors records
    uint64_t tx_windows_errors; //transmit windows errors records
    uint64_t tx_fifo_errors;    //transmit fifo errors records
    uint64_t tx_dropped;        //transmit dropped records

    uint64_t rx_errors;        //receive error
    uint64_t rx_length_errors; //receive length errors
    uint64_t rx_missed_errors; //receive missed errors
    uint64_t rx_fifo_errors;   //receive fifo errors
    uint64_t rx_crc_errors;    //receive crc check errors
    uint64_t rx_frame_errors;  //receive frame error
    uint64_t rx_dropped;       //receive dropped records

    uint64_t tx_packets; //transmit packet numbers
    uint64_t tx_bytes;   ///transmit byte numbers

    uint64_t collisions; //collisions count
} net_device_status_t;

typedef struct
{
    device_object_t *device_object; //device object

    uint32_t io_addr;
    uint8_t mac_addr[10];
    int drv_flags; //driver flags
    int flags;
    irqno_t irq;
    pci_dev_t *pci_device;

    uint32_t device_features; //device features

    net_device_status_t status; //device status
    rtl_extra_status_t xstatus; //extension status

    //rx
    uint8_t *rx_buffer;
    uint8_t *rx_ring;
    uint8_t current_rx; //current address of packet read
    flags_t rx_flags;
    dma_addr_t rx_ring_dma; //dma address
    rtl8139_status_t rx_status;

    //tx
    uint8_t *tx_buffers;
    uint8_t *tx_buffer[NUM_TX_DESC];
    flags_t tx_flags;
    uint64_t current_tx;      //current transport
    uint64_t dirty_tx;        //transport had been used
    atomic_t tx_free_counts;  //free transport number
    dma_addr_t tx_buffer_dma; //dma address
    rtl8139_status_t tx_status;

    chip_t chipset; //chipsets

    spinlock_t lock;    //lock
    spinlock_t rx_lock; //receive lock

    uint32_t rx_config; //receive config

    device_queue_t rx_queue; //receive queue
} device_extension_t;

typedef struct rx_packet_header
{
    uint16_t status;
    uint16_t length;
} rx_packet_header_t;

//rx config default
static const uint32_t rtl8139_rx_config = {RX_CFG_RECV_32K | RX_NO_WRAP | RX_CFG_FIFO_NONE | RX_CFG_DMA_UNLIMITED};
//tx config default
static const uint32_t rtl8139_tx_config = {TX_IFG96 | TX_DMA_1024 | TX_RETRY_8};
//interrupt mask
static const uint16_t rtl8139_intr_mask = {PCI_ERR | PCS_TIMEOUT | RX_UNDERRUN | RX_OVERFLOW | RX_FIFO_OVER | TX_ERR | TX_OK | RX_ERR | RX_OK};

#endif
